package disjunction
{
	import disjunction.timing.SimulationTimer;
	
	import flash.events.EventDispatcher;
	import flash.events.TimerEvent;
	
	/**
	 * A self-updated controller using its own timer. Can be used for self-updating
	 * or manually-updated controllers. The benefit to having both functionalities
	 * in one is that it can be adapted as necessary (eg. auto-turns in a TBG).
	 * 
	 * @author Nick Wiggill
	 */
	
	public class TimedUpdater extends EventDispatcher
	{
		protected var _timer:SimulationTimer;
		
		/**
		 * Set up the timer object to tick in the background, if applicable.
		 * 
		 * @param updateIntervalMs The desired period per timer tick, in milliseconds.
		 * Specify 0 if Controller updates are to be called manually (turn-based).
		 * @param updateTimeoutMs The desired period per timer tick, in milliseconds.
		 * Specify 0 if no timeout is not applicable.
		 */
		public function TimedUpdater()
		{
			//set up a non-functioning timer, just so that we can set the listener ASAP.
			_timer = new SimulationTimer(0, 0, 0);
			_timer.addEventListener(TimerEvent.TIMER, tick);
		}
		
		//Would just be called initialise, but due to subclasses using that method name,
		//and AS3 lacking functional polymorphism, we name it thus instead.
		public function initialiseTiming(config:TimingConfig):void
		{
			_timer.baseUpdateIntervalMs = config.updateIntervalMs;
			_timer.updateTimeoutMs = config.updateTimeoutMs;
		}
		
		public function start():void
		{
			if (isRealTime)
				_timer.start();
		}
		
		public function stop():void
		{
			if (isRealTime)
				_timer.stop();
		}
		
		/** Ticks are irregular, so consume time in dt-sized chunks to apply controller ops */
		private function tick(e:TimerEvent):void
		{
			while (_timer.consumeInterval())
			{
				//pass in the interval we are consuming, for use in update as dt
				update(_timer.updateIntervalMs);
			}
		}

		public function get isRealTime():Boolean
		{
			return _timer.updateIntervalMs > 0;
		}
		
		/** (abstract) When subclassing, place your update logic here. */
		protected function update(timeDeltaMs:uint):void
		{
		}
	}
}